// 
// Copyright 2010 Classpath Pty Ltd <opensource@classpath.com.au>
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 

**
** This class provides the interface between a `Migration` and database specific SQL operations.
**
abstract class Adapter {

    **
    ** This map stores the mappings between a particular `Modification` class and its handler method within this class.
    ** Overriding methods which wish to handle additional `Modification` types need to ensure that it is registered with this map before `Adapter.sql` is called.
    **
    [Type:Method] handlers := [:]

    **
    ** Creates a new `Adapter` registering the various handler methods below.
    **
    protected new make() {
        Pod.of(this).log.debug("${typeof}.make - start")
        handlers[CreatedTable#] = #createTableSql
        handlers[AlteredTable#] = #alterTableSql
        handlers[DroppedTable#] = #dropTableSql
        handlers[ExecutedSql#] = #executeSql
        Pod.of(this).log.debug("${typeof}.make - end")
    }

    **
    ** Generates SQL for the supplied `Modification` type.
    ** This method looks up the type of the supplied modification against the `Adapter.handlers` map to find a handler for the supplied class.
    ** An `sys::Err` is thrown if a handler is not registered for the supplied modification type.
    ** This means that if you subclass one of the existing tables, you'll need to ensure its type is also registered with a handler (pain in the ass? yes! but a whole lot less painful than trekking through class hierarchies!)
    **
    Str sql(Modification modification) {
        Pod.of(this).log.debug("${typeof}.sql(${modification}) - start")
        handler := handlers[modification.typeof]
        if (handler == null) {
            Pod.of(this).log.err("${typeof} doesn't know how to generate SQL for ${modification.typeof} (did you register it?)")
            throw Err("${typeof} doesn't know how to generate SQL for ${modification.typeof} (did you register it?)")
        }
        sql := handler.callOn(this, [modification])
        Pod.of(this).log.debug("${typeof}.sql(${modification}) - end - returning ${sql}")
        return sql
    }

    **
    ** Implementers of this class should override this method to generate 'CREATE TABLE' SQL for the supplied `CreatedTable`.
    **
    abstract Str createTableSql(CreatedTable table)

    **
    ** Implementers of this class should override this method to generate 'ALTER TABLE' SQL for the supplied `AlteredTable`.
    **
    abstract Str alterTableSql(AlteredTable table)

    **
    ** Implementers of this class should override this method to generate 'DROP TABLE' SQL for the supplied `DroppedTable`.
    **
    abstract Str dropTableSql(DroppedTable table)

    **
    ** Implementers of this class should override this method to generate SQL for the supplied `ExecutedSql` (chances are you'll just want to return sql.sql).
    **
    abstract Str executeSql(ExecutedSql sql)

    **
    ** Implementers of this class should override this method to generate SQL for a prepared statement with paramters '@from' and '@to' for logging an update to the version history table created in `MigrationZero`.
    **
    abstract Str logMigrationSql()

    **
    ** Implementers of this class should override this method to generate SQL to select the latest version from the version history table created in `MigrationZero`.
    **
    abstract Str dbVersionSql()

}
